package com.wocai.jrt.orders.service.impl;

import java.io.File;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.inject.Named;

import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.vteba.utils.common.PropsUtils;
import com.vteba.utils.id.ObjectId;
import com.wocai.jrt.employee.model.Org;
import com.wocai.jrt.employee.service.spi.OrgService;
import com.wocai.jrt.investor.model.Investor;
import com.wocai.jrt.investor.service.spi.InvestorService;
import com.wocai.jrt.orders.model.ContactHistory;
import com.wocai.jrt.orders.model.Orders;
import com.wocai.jrt.orders.service.spi.ContactHistoryService;
import com.wocai.jrt.orders.service.spi.ContactService;
import com.wocai.jrt.orders.service.spi.OrdersService;
import com.wocai.jrt.product.model.Product;
import com.wocai.jrt.product.model.ProductGrade;
import com.wocai.jrt.product.service.spi.ProductGradeService;
import com.wocai.jrt.product.service.spi.ProductService;
import com.wocai.jrt.utils.ESignUtils;
import com.wocai.jrt.utils.EmailUtils;
import com.wocai.jrt.utils.MyFileUtils;
import com.wocai.jrt.utils.NumberToCNUtils;
import com.wocai.jrt.utils.WPS2PDFUtils;
import com.wocai.jrt.utils.WordFormatter;
import com.wocai.jrt.utils.WordUtils;

@Named
public class ContactServiceImpl implements ContactService {
	private static final Logger LOGGER = LoggerFactory.getLogger(ContactServiceImpl.class);

	@Inject
	private OrdersService ordersServiceImpl;
	@Inject
	private ProductService productServiceImpl;
	@Inject
	private InvestorService investorServiceImpl;
	@Inject
	private OrgService orgServiceImpl;
	@Inject
	private ContactHistoryService contactHistoryServiceImpl;
	@Inject
	private ProductGradeService productGradeServiceImpl;

	@Override
	public String create(String orderId) throws Exception {
		Orders orderParam = new Orders();
		orderParam.setOrderId(orderId);
		Orders order = ordersServiceImpl.unique(orderParam);

		// '订单状态 1已支付2未支付3已兑付4部分支付5已取消6已完成7即将到期8带兑付'
		Integer[] states = { 2, 3, 4, 5 };
		List<Integer> stateList = new ArrayList<Integer>(Arrays.asList(states));
		if (null == order || stateList.contains(order.getState())) {
			return null;
		}

		Investor investor = investorServiceImpl.get(order.getInvestorId());
		Product product = productServiceImpl.get(order.getProductId());

		// 产品合同原件
		String contactPath = product.getContactFile();

		// 用户（投资人）各自合并签名后的合同路径
		String userContactPath = null;
		if (!StringUtils.isBlank(contactPath)) {
			if (contactPath.toLowerCase().endsWith(".docx")) {

				Map<String, String> map = new HashMap<String, String>();
				WordFormatter wf = new WordFormatter();

				// 生成订单合同编号，规则产品合同前缀+日期（yyyyMMdd）+6位产品递增数
				String contactNum = null;
				String orderContactNum = order.getContactNum();
				if (StringUtils.isBlank(orderContactNum)) {
					contactNum = createContactNum(product.getContactNum());
					orderContactNum = product.getContactPrefix()
							+ new SimpleDateFormat("MMdd").format(new Date()) + contactNum;
					LOGGER.info("create order contact number success, orderContactNum=[{}]",
							orderContactNum);
				}

				// 订单合同编号
				wf.setContractNumber(orderContactNum);
				wf.setInvestorName(investor.getName());

				// 投资人签名，这里是图片路径
				String investorSignName = PropsUtils.get("images.url") + order.getContactSignUser();
				wf.setInvestorSignName(investorSignName);
				LOGGER.info("set investorSign path success, investorSignPath=[{}]",
						investorSignName);

				// 签单时间
				String signTime = new SimpleDateFormat("yyyy年MM月dd日").format(new Date());
				wf.setSignTime(signTime);
				LOGGER.info("create signTime success, signTime=[{}]", signTime);

				// 投资金额
				double orderAmount = order.getOrderAmount();
				DecimalFormat format = new DecimalFormat("#,##0.00");
				wf.setAmount(format.format(orderAmount));

				// 投资金额大写
				wf.setAmountToCN(NumberToCNUtils.number2CNMontrayUnit(BigDecimal
						.valueOf(orderAmount)));
				LOGGER.info("set orderAmount success, orderAmount=[{}]", orderAmount);

				// 证件号
				wf.setIDCard(investor.getIdcard());

				// 通信地址
				wf.setAddress(investor.getAddress());

				// 联系电话，模板占位符区分大小写，且不允许带字符格式
				wf.setPhone(investor.getMobile());

				// 邮件
				wf.setEmail(investor.getEmail());

				// 开户行
				wf.setBankName(order.getBankDeposit());

				// 开户名
				wf.setAccountName(order.getBankName());

				// 银行帐（卡）号
				wf.setBankAccount(order.getBankAccount());

				// 1.如果存在收益分档，截止日期和预期收益取收益分档的数据
				// 2.如果收益分档不存在，截止日期不填写，预期收益取基本信息的预期收益
				String gradeId = order.getGradeId();
				if (StringUtils.isNotBlank(gradeId)) {
					ProductGrade productGrade = productGradeServiceImpl.get(gradeId);
					Date expireDate = productGrade.getExpireDate();
					if (null != expireDate) {
						wf.setExpireDate(new SimpleDateFormat("yyyy年MM月dd日").format(expireDate));
					}
					wf.setProspectiveEarnings(productGrade.getProspectiveEarnings());
				} else {
					wf.setProspectiveEarnings(product.getProspectiveEarnings());
				}

				if (StringUtils.isNotBlank(order.getElectronic())) {
					String electronicPath = PropsUtils.get("images.url") + order.getElectronic();
					wf.setElectronic(electronicPath);
					LOGGER.info("electronicPath=[{}]", electronicPath);
				}

				// 通过类反射机制生成替换占位符的map数据
				Field[] fields = wf.getClass().getDeclaredFields();
				for (Field field : fields) {
					field.setAccessible(true);
					String fieldValue = String.valueOf(field.get(wf));
					if (!"null".equals(fieldValue)) {
						map.put(field.getName(), fieldValue);
					} else {
						map.put(field.getName(), "");
					}

				}
				map.put("[", "");
				map.put("]", "");

				// 生成中间文件路径，中间文件不会被删除，作为备份
				String filename = new File(contactPath).getName();
				String docxPath = MyFileUtils.getFilePath(filename, MyFileUtils.DOC_TYPE);

				// 生成中间文件，即替换占位符生成新的docx文件，注：contactPath带占位符合同路径，docxPath替换后中间文件路径
				WordUtils.searchAndReplace(contactPath, docxPath, map);
				LOGGER.info("replace contact file success, contactPath=[{}], docxPath=[{}]",
						contactPath, docxPath);

				// 生成最终的pdf文件路径
				userContactPath = MyFileUtils.getFilePath(
						filename.replace(".docx", wf.getContractNumber() + ".pdf"),
						MyFileUtils.PDF_TYPE);

				// 生成最终的pdf文件，即将中间文件docx转换成pdf文件即可,userContactPath:目标文件路径
				WPS2PDFUtils.word2PDF(docxPath, userContactPath);
				LOGGER.info("convert word to pdf success, docxPath=[{}], userContactPath=[{}]",
						docxPath, userContactPath);

				Org org = orgServiceImpl.get(order.getOrgId());

				int isEsign = 0;
				if ("身份证".equals(investor.getIdType())) {
					String resultPath = ESignUtils.sign(investor, org, userContactPath);
					if (StringUtils.isNotBlank(resultPath)) {
						userContactPath = resultPath;
						isEsign = 1;
					}
				}

				// 更新产品合同数字
				if (StringUtils.isNotBlank(contactNum)) {
					Product productParam = new Product();
					String productId = product.getId();
					productParam.setId(productId);

					// contactNum当这个为null时说明电子合同是重新生成的
					productParam.setContactNum(contactNum);
					productServiceImpl.updateById(productParam);
					LOGGER.info(
							"update product contactNum success,  productId=[{}], contactNum=[{}]",
							productId, contactNum);
				}

				// 更新订单合同编号
				Orders orderData = new Orders();

				// 这里不是orderId而是id
				orderData.setId(order.getId());
				orderData.setContactNum(orderContactNum);
				orderData.setContactMidFile(docxPath);
				orderData.setPaySignUser(userContactPath);
				orderData.setIsEsign(String.valueOf(isEsign));
				ordersServiceImpl.updateById(orderData);
				LOGGER.info(
						"update order orderContactNum success,  orderId=[{}], orderContactNum=[{}]",
						orderId, orderContactNum);

				// 插入到合同历史记录里
				ContactHistory contactHistory = new ContactHistory();
				contactHistory.setId(ObjectId.get().toString());
				contactHistory.setOrderId(orderId);
				contactHistory.setContactSignUser(order.getContactSignUser());
				contactHistory.setContactMidFile(docxPath);
				contactHistory.setContactFile(userContactPath);
				contactHistory.setContactName(new File(userContactPath).getName());
				contactHistory.setCreateTime(new Date());

				contactHistoryServiceImpl.save(contactHistory);
				LOGGER.info("save contactHistory success,  orderId=[{}], userContactPath=[{}]",
						orderId, userContactPath);

				// 发送电子合同
				try {
					if (StringUtils.isNotBlank(investor.getEmail())) {
						EmailUtils se = new EmailUtils(false);
						List<File> affix = new ArrayList<File>();
						affix.add(new File(userContactPath));
						se.doSendHtmlEmail(product.getBriefName() + "产品基金合同",
								"您购买的" + product.getBriefName() + "产品的基金合同，请查收",
								investor.getEmail(), affix);//
						LOGGER.info("send order contact email success!, email=[{}]",
								investor.getEmail());
					} else {
						LOGGER.info("send order contact email failure caused by investor email is null!");
					}
				} catch (Exception e) {
					LOGGER.error("exeption by send email , msg=[{}]", e.getMessage());
				}

				// Pad端投资人签订合同成功,提醒投后APP用户
				try {
					if (StringUtils.isNotBlank(contactNum)) {
						ordersServiceImpl.createContractMessage(orderId);
						LOGGER.info("send jiguang success");
					}
				} catch (Exception e) {
					LOGGER.error("exeption by jiguang , msg=[{}]", e.getMessage());
				}
			} else {
				LOGGER.error("not support other file format but docx, userContactPath=[{}]",
						userContactPath);
			}
		}

		return userContactPath;
	}

	private String createContactNum(String code) {
		int num = StringUtils.isBlank(code) ? 0 : Integer.valueOf(code);
		num++;
		code = String.valueOf(num);
		int leng = code.length();
		if (leng == 1) {
			code = "00000" + num;
		} else if (leng == 2) {
			code = "0000" + num;
		} else if (leng == 3) {
			code = "000" + num;
		} else if (leng == 4) {
			code = "00" + num;
		} else if (leng == 5) {
			code = "0" + num;
		}

		return code;
	}

}
